package com.lujianfei.powersearch.base

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableArrayList
import androidx.databinding.ObservableList
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.RecyclerView
import com.lujianfei.powersearch.utils.DatabindingDiffUtils


/**
 * AvatalkBaseAdapter
 *
 * @author Robin
 * @date 4/4/21
 */

abstract class BaseDatabindingAdapter<M, B : ViewDataBinding>(private var items: ObservableArrayList<M>) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){

    private val dataListChangedCallback = ListChangedCallback()

    fun getItemsData(): ObservableArrayList<M> {
        return items
    }

    class BaseBindingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    interface OnItemClickListener<M> {
        fun onItemClick(bean: M)
    }

    fun setDatas(newList: MutableList<M>) {
        DatabindingDiffUtils.setData(oldList = items, newList = newList)
    }
    /**
     * 重写id可以使刷新不闪烁
     */
    override fun getItemId(position: Int): Long {
        var position = position
        if (position >= items.size) {
            return System.currentTimeMillis()
        }
        items[position]?.let {
            return it.toString().hashCode().toLong()
        }
        return System.currentTimeMillis()
    }

    override fun getItemCount(): Int {
        return if(items.isNullOrEmpty()) 0 else items.size
    }

    override fun getItemViewType(position: Int): Int {
        return super.getItemViewType(position)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val binding: B = DataBindingUtil.inflate(LayoutInflater.from(parent.context), getLayoutResId(), parent, false)
        return BaseBindingViewHolder(binding.root)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        try {
            if (holder is BaseBindingViewHolder) {
                val bean : M = items[position]
                val binding: B? = DataBindingUtil.getBinding(holder.itemView)
                onBindItem(binding, bean, position)
                binding?.executePendingBindings()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        items.addOnListChangedCallback(dataListChangedCallback)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        items.removeOnListChangedCallback(dataListChangedCallback)
    }

    @LayoutRes
    protected abstract fun getLayoutResId(): Int

    protected abstract fun onBindItem(binding: B?, bean: M, position: Int)

    /**
     * 额外监听数据变化，这样就可以直接更新数据，
     * 而不用每次都调用notifyDataSetChanged()等方式更新数据
     *
     *
     * 我只对插入和移除做了监听处理，其他方式没有处理
     * 小伙伴可以根据自己的具体需要做额外处理
     */
    inner class ListChangedCallback : ObservableList.OnListChangedCallback<ObservableArrayList<*>>() {
        override fun onChanged(newItems: ObservableArrayList<*>) {
            notifyDataSetChanged()
        }

        override fun onItemRangeChanged(newItems: ObservableArrayList<*>, positionStart: Int, itemCount: Int) {
            notifyItemRangeChanged(positionStart, itemCount ,"")
        }

        override fun onItemRangeInserted(newItems: ObservableArrayList<*>, positionStart: Int, itemCount: Int) {
            notifyItemRangeInserted(positionStart, itemCount)
        }

        override fun onItemRangeMoved(newItems: ObservableArrayList<*>, fromPosition: Int, toPosition: Int, itemCount: Int) {
            if (itemCount == 1) {
                notifyItemMoved(fromPosition, toPosition)
            } else {
                notifyDataSetChanged()
            }
        }

        override fun onItemRangeRemoved(newItems: ObservableArrayList<*>, positionStart: Int, itemCount: Int) {
            notifyItemRangeRemoved(positionStart, itemCount)
        }
    }
}